package org.feng.annotation.interpret;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.feng.annotation.AccessLog;
import org.feng.entity.PubLog;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;

/**
 * 日志注解解释器
 *
 * @author : FengShuai
 * @since : 2024/6/27 9:24
 */
@Component
@Aspect
@Slf4j
public class LogInterpret {

    @Around(value = "@annotation(accessLog)")
    public Object around(ProceedingJoinPoint point, AccessLog accessLog) throws Throwable {
        Object proceed;
        long startTime = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null){
            return point.proceed();
        }
        HttpServletRequest request = attributes.getRequest();
        String url = request.getRequestURL().toString();
        String ip = request.getRemoteAddr();
        String browser = request.getHeader("User-Agent");
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();
        String requestMethod = request.getMethod();
        PubLog pubLog = new PubLog();
        pubLog.setUrl(url);
        pubLog.setIp(ip);
        pubLog.setBrowser(browser);
        pubLog.setMethod(className + "." + methodName);
        pubLog.setRemark(accessLog.value());
        pubLog.setCreateTime(LocalDateTime.now());
        pubLog.setRequestMethod(requestMethod);
        pubLog.setParams(getRequestParams(request));
        pubLog.setBody(getRequestBody(point));
        pubLog.setPlatform(accessLog.platform());
        proceed = point.proceed();
        try {
            pubLog.setUserId(StpUtil.getLoginIdAsLong());
        } catch (Exception e) {
            log.info("日志获取用户信息失败");
        }
        pubLog.setResponseBody(JSON.toJSONString(proceed));
        long endTime = System.currentTimeMillis();
        pubLog.setRequestTime(String.valueOf(endTime - startTime));
        pubLog.insert();
        return proceed;
    }

    /**
     * 获取get请求参数
     *
     * @param request request
     * @return 请求参数
     */
    private String getRequestParams(HttpServletRequest request) {
        StringBuilder params = new StringBuilder();
        request.getParameterMap().forEach((key, value) -> params.append(key).append("=").append(String.join(",", value)).append("&"));
        return params.length() == 0 ? null : params.substring(0, params.toString().length() - 1);
    }

    /**
     * 获取请求体参数
     *
     * @param point point
     * @return 请求体参数
     */
    private String getRequestBody(ProceedingJoinPoint point) {
        Object[] args = point.getArgs();
        StringBuilder params = new StringBuilder();
        if (args != null) {
            for (Object arg : args) {
                params.append(JSON.toJSONString(arg));
            }
        }
        return params.toString();
    }
}
